package com.sms.web.system.service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.sms.common.Constants;
import com.sms.common.exception.SystemException;
import com.sms.common.persistence.DynamicSpecifications;
import com.sms.common.persistence.Operator;
import com.sms.common.persistence.SearchFilter;
import com.sms.utils.ServletContextHolder;
import com.sms.utils.TokenUtils;
import com.sms.web.system.dao.SysMenuDao;
import com.sms.web.system.dao.SysUserDao;
import com.sms.web.system.dao.SysUserRoleDao;
import com.sms.web.system.entity.SysMenu;
import com.sms.web.system.entity.SysRole;
import com.sms.web.system.entity.SysUser;
import com.sms.web.system.entity.SysUserRole;
import com.sms.web.utils.UserUtils;
import com.sms.web.vo.SysUserVo;

/**
 * @desc 
 * @author wjw
 * @time 2017年11月16日下午3:34:16
 */
@Service
@Transactional
public class SysUserService {
    
    protected Logger logger = LoggerFactory.getLogger(getClass());
    
    @Autowired
    private SysUserDao userDao;
    @Autowired
    private SysUserRoleDao urDao;
    @Autowired
    private SysMenuDao menuDao;
    
    
    /**
     * 用户登录
     * @param id
     * @return
     */
    public SysUser login(String username, String password) throws SystemException {
    	SysUser user = userDao.login(username, password);
    	if( user== null) {
    		throw new SystemException("用户名不存在或密码错误");
    	}
    	//超级管理员查询全部权限
    	if(username.equals("admin") || username.equals("superadmin")) {
    		//1.查询全部权限菜单添加到menuList中
    		List<SysMenu> menuList = menuDao.findAllMenu();
    		user.setMenuList(menuList);
    	}else {
    		//1.查询用户权限添加到menuList中
    		List<SysMenu> menuList = menuDao.findByRoleId(user.getId());
    		user.setMenuList(menuList);
    	}
    	//2.生成用户token
    	String token = TokenUtils.token();
    	user.setToken(token);
    	//3.将用户添加到session中
    	HttpSession session = ServletContextHolder.getSession();
    	session.setAttribute(Constants.USER_SESSION_NAME, user);
    	//4.将用户添加到缓存中
    	TokenUtils.putUser(token, user);
        return user;
    }
    
    /**
     * 用户退出
     * @param id
     * @return
     */
    public void logout() {
    	HttpSession session = ServletContextHolder.getSession();
    	SysUser user = (SysUser) session.getAttribute(Constants.USER_SESSION_NAME);
    	if(user!=null && StringUtils.isNotBlank(user.getToken())){
    		//清除缓存user对象
    		TokenUtils.remove(user.getToken());
    		//清楚session user对象
    		session.setAttribute(Constants.USER_SESSION_NAME, null);
    	}
    }
    
    /**
     * 根据id查找用户
     * @param id
     * @return
     */
    @Transactional(readOnly = true)
    public SysUser findUser(String id) {
        return userDao.getOne(id);
    }
    
    /**
     * 查找当前用户
     * @return 当前用户
     */
    @Transactional(readOnly = true)
    public SysUser findCurrentUser() {
        String id = UserUtils.getUserId();
        return userDao.getOne(id);
    }
    
    /**
     * 保存用户
     * @param entity
     * @return
     */
    public SysUser saveUser(SysUserVo entity) {
    	//1.保存用户信息
    	SysUser user = userDao.save(entity);
    	//保存用户角色信息
    	SysUserRole ur = new SysUserRole();
    	ur.setRole(new SysRole(entity.getRoleId()));
    	ur.setUser(user);
    	urDao.save(ur);
        return user;
    }
    
    /**
     * 逻辑删除用户
     * @param id
     */
    public void deleteUser(String id) {
        userDao.setDelFlag(id);
    }
    
    /**
     * 分页查询用户 (按id降序排序)
     * @param serchkey
     * @param pageNumber
     * @param pageSize
     * @return
     */
    @Transactional(readOnly = true)
    public Page<SysUser> findByKeyword(String serchkey, int pageNumber, int pageSize) {
    	//1.定义jpa分页对象
    	Sort sort = new Sort(Direction.DESC, "id");
        PageRequest pageRequest = PageRequest.of(pageNumber - 1, pageSize, sort);
        //2.构建动态查询条件
        Collection<SearchFilter> filters = new ArrayList<>();
        filters.add(new SearchFilter("username", Operator.LIKE , serchkey));//模糊匹配账户
        filters.add(new SearchFilter("username", Operator.NEQ , "admin"));//不查询超级管理员
        filters.add(new SearchFilter("username", Operator.NEQ , "superadmin"));//模糊匹配账户
        filters.add(new SearchFilter("delFlag", Operator.EQ , "0"));//查询未删除数据
        Specification<SysUser> spec = DynamicSpecifications.bySearchFilter(filters, SysUser.class);
        return userDao.findAll(spec, pageRequest);
    }
    
    /**
     * 构建查询条件（只查找该根节点下面数据）
     * @param keyword
     * @return
     */
    private Specification<SysUser> buildSpecification(final String keyword) {
        Specification<SysUser> spec = new Specification<SysUser>() {
            
            @Override
            public Predicate toPredicate(Root<SysUser> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
                List<Predicate> predicates = new ArrayList<Predicate>();
                if (StringUtils.isNotEmpty(keyword)) {// 根据name like
                    String queryKey = convertMySqlString(keyword);
                    Path<String> expression = root.get("username");
                    Predicate predicateName = builder.like(expression, "%" + queryKey + "%", '/');
                    predicates.add(builder.or(predicateName));
                }
                //不查询超级管理员账户admin或superadmin
                predicates.add(builder.notEqual(root.get("username"), "admin"));
                predicates.add(builder.notEqual(root.get("username"), "superadmin"));
                predicates.add(builder.equal(root.get("delFlag"), "0"));
                // 将所有条件用 and 联合起来
                if (predicates.size() > 0) {
                    return builder.and(predicates.toArray(new Predicate[predicates.size()]));
                }
                
                return builder.conjunction();
            }
        };
        return spec;
    }
    
    /**
     * mysql模糊查询时，如果查询关键字本身包含_和%，需要转义
     * @param queryKey 查询关键字
     * @return 转义字符
     */
    private String convertMySqlString(String queryKey) {
        String[] encodeArr = { "_", "%" };
        String rst = queryKey;
        for (String encode : encodeArr) {
            rst = StringUtils.replace(rst, encode, "/" + encode);
        }
        return rst;
    }
    
    /**
     * 根据用户名查找用户
     * @param username
     * @return
     */
    @Transactional(readOnly = true)
    public SysUser findByUsername(String username){
        return userDao.findByUsername(username);
    }
    
    /**
     * 修改密码
     * @param password password
     * @param userId userId
     */
    public void updatePasswordById(String password, String id) {
        userDao.updatePasswordById(password, new Date(), id);
    }
}
